﻿using Aribaccio.Logger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Aribaccio.Device
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TPara"></typeparam>
    public class DeviceSerialAscii<TPara> : DeviceSerial<TPara> where TPara : IDevicePara
    {
        /// <summary>
        /// 是否回车结束符
        /// </summary>
        protected bool IsCarriageEndof { get; set; }
        /// <summary>
        /// 是否在发送前清除缓冲
        /// </summary>
        protected bool IsClearCacheBeforeRead { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="argDevicePara">设备参数接口</param>
        public DeviceSerialAscii(TPara argDevicePara)
            : base(argDevicePara)
        {
            if (!this.IsAutoReceivedMode)
            {
                this.SleepTime = 1000;
                this.ReceiveTimeout = 2500;
            }          
            this.IsCarriageEndof = false;
            this.IsClearCacheBeforeRead = false;
        }

        /// <summary>
        /// 发送串口数据
        /// </summary>
        /// <typeparam name="TInput">输入结构类型</typeparam>
        /// <param name="argNodeItem">指令节点数据对象</param>
        /// <returns>返回结果对象</returns>
        public Result WriteAsciiData<TInput>(TInput argNodeItem) where TInput : AsciiSlaveData, new()
        {
            lock (Locker)
            {
                Result ResultData = new Result(ResultStatus.Failure);
                if (argNodeItem == null) { return ResultData; }
                try
                {
                    //如果需要进一步校验
                    ResultModel<byte[]> ResultObjItem = this.SlaveSerialData(argNodeItem, argNodeItem.IsWaitResult);
                    //判断是否成功
                    if (ResultObjItem.ResultState && ResultObjItem.Data != null && ResultObjItem.Data.Length >= base.NodeDataNum)
                    {
                        ResultData.ResultCode = ResultStatus.Succeed;
                    }
                    else
                    {
                        ResultData.ResultCode = !ResultObjItem.ResultState ? ResultObjItem.ResultCode : ResultStatus.Failure;
                        ResultData.ResultMsg = !ResultObjItem.ResultState ? ResultObjItem.ResultMsg : "[" + base.DevicePara.DeviceCaption + "][读取串口数据]->发送数据失败";
                    }
                }
                catch (Exception ep)
                {
                    ResultData.ResultCode = ResultStatus.Exception;
                    ResultData.ResultMsg = "[" + base.DevicePara.DeviceCaption + "][发送串口数据]->异常：" + ep.Message;
                }
                return ResultData;
            }
        }

        /// <summary>
        /// 读取串口数据
        /// </summary>
        /// <typeparam name="TInput">输入结构类型</typeparam>
        /// <typeparam name="TOutput">输出结构类型</typeparam>
        /// <param name="argNodeItem">指令节点数据对象</param>
        /// <returns>返回接收指令节点数据的结果对象 </returns>
        public ResultModel<TOutput> ReadAsciiData<TInput, TOutput>(TInput argInputNodeItem, TOutput argOutputSlave)
            where TInput : AsciiSlaveData, new()
            where TOutput : AsciiSlaveData, new()
        {
            lock (Locker)
            {
                ResultModel<TOutput> ResultData = new ResultModel<TOutput>(ResultStatus.Failure, new TOutput() { Command = argOutputSlave.Command, IsWaitResult = argOutputSlave.IsWaitResult });
                if (argInputNodeItem == null) { return ResultData; }
                try
                {
                    //解析，读取数据
                    ResultModel<byte[]> ResultObj = this.SlaveSerialData(argInputNodeItem, argInputNodeItem.IsWaitResult);
                    //判断是否读取成功
                    if (ResultObj.ResultState && ResultObj.Data != null)
                    {
                        if (argInputNodeItem.IsWaitResult && ResultData.Data != null)
                        {
                            string strResultData = ResultObj.Data.ToAsciiString();
                            if (!string.IsNullOrEmpty(argOutputSlave.Command) && strResultData.StartsWith(argOutputSlave.Command, StringComparison.OrdinalIgnoreCase))
                            {
                                int nCommandLength = argOutputSlave.Command.Length;
                                string strData = strResultData.Substring(nCommandLength, strResultData.Length - nCommandLength);
                                ResultData.Data.UpdateData(strData);
                                ResultData.ResultCode = ResultStatus.Succeed;
                            }
                            else
                            {
                                ResultData.Data.UpdateData(strResultData);
                                ResultData.ResultCode = ResultStatus.Failure;
                                ResultData.ResultMsg = !ResultObj.ResultState ? ResultObj.ResultMsg : "[" + base.DevicePara.DeviceCaption + "][读取串口数据]->校验指令失败";
                            }
                        }
                        else
                        {
                            ResultData.ResultCode = ResultStatus.Succeed;
                        }
                    }
                    else
                    {
                        ResultData.ResultCode = ResultStatus.Failure;
                        ResultData.ResultMsg = !ResultObj.ResultState ? ResultObj.ResultMsg : "[" + base.DevicePara.DeviceCaption + "][读取串口数据]->读取数据失败";
                    }
                }
                catch (Exception ep)
                {
                    ResultData.ResultCode = ResultStatus.Exception;
                    ResultData.ResultMsg = "[" + base.DevicePara.DeviceCaption + "][读取串口数据]->异常：" + ep.Message;
                }
                return ResultData;
            }
        }

        /// <summary>
        /// 读取串口的数据
        /// </summary>
        /// <param name="argInputNodeItem">发送指令节点数据对象</param>
        /// <param name="IsWaitResultRead">是否读取等待</param>
        /// <returns>返回接收字节的结果对象</returns>
        protected ResultModel<byte[]> SlaveSerialData<TInput>(TInput argInputNodeItem, bool IsWaitResultRead)
            where TInput : AsciiSlaveData, new()
        {
            //获取锁
            base.HybirdLock.Enter();
            ResultModel<byte[]> ResultData = new ResultModel<byte[]>(ResultStatus.Failure);
            //解析节点数据
            ResultModel<byte[]> ResultObjData = this.ParseNodeData(argInputNodeItem);
            if (ResultObjData.ResultState && ResultObjData.Data != null && ResultObjData.Data.Length > 0)
            {
                //判断是否需要清除缓存
                if (this.IsClearCacheBeforeRead) { base.RreadSerialPortData(false); }
                if (IsWaitResultRead)
                {
                    for (int i = 0; i < base.ReceiveTimeoutNum; i++)
                    {
                        //发送串口指令
                        base.SendSerialPortData(ResultObjData.Data);
                        //读取数据
                        ResultData = base.RreadSerialPortData(true);
                        //判断是否读取成功
                        if (ResultData.ResultState && ResultData.Data != null)
                        {
                            break;
                        }
                        else
                        {
                            LoggerMgrcore.Instance.WriteDebug($"{this.DevicePara.DeviceName} SlaveSerialData RreadSerialPortData[{i}] error ：{ResultData.ResultMsg}");
                        }
                    }
                }
                else
                {
                    Result SendResult = base.SendSerialPortData(ResultObjData.Data);
                    ResultData.ResultCode = SendResult.ResultCode;
                    ResultData.ResultMsg = SendResult.ResultMsg;
                }
                //离开锁
                base.HybirdLock.Leave();
            }
            else
            {
                //离开锁
                base.HybirdLock.Leave();
                ResultData = ResultObjData;
            }
            return ResultData;
        }

        /// <summary>
        /// 解析指令数据
        /// </summary>
        /// <param name="argNodeItem">指令节点数据对象</param>
        /// <returns>返回接收字节的结果对象</returns>
        protected ResultModel<byte[]> ParseNodeData<TInput>(TInput argNodeItem)
            where TInput : AsciiSlaveData, new()
        {
            lock (argNodeItem)
            {
                ResultModel<byte[]> ResultData = new ResultModel<byte[]>(ResultStatus.Failure);
                if (argNodeItem == null || string.IsNullOrEmpty(argNodeItem.Command)) { return ResultData; }
                try
                {
                    List<byte> resultBytes = new List<byte>();
                    //指令
                    resultBytes.AddRange(argNodeItem.Command.ToAsciiBytes());
                    //数据体
                    if (!string.IsNullOrEmpty(argNodeItem.Data))
                    {
                        resultBytes.AddRange(argNodeItem.Data.ToAsciiBytes());
                    }
                    //检查 结束符
                    if (this.IsCarriageEndof)
                    {
                        resultBytes.Add(argNodeItem.CarriageReturn);
                    }
                    //最后赋值
                    ResultData.ResultCode = ResultStatus.Succeed;
                    ResultData.Data = resultBytes.ToArray();
                }
                catch (Exception ep)
                {
                    ResultData.ResultCode = ResultStatus.Exception;
                    ResultData.ResultMsg = "[" + base.DevicePara.DeviceCaption + "][解析指令数据]->异常：" + ep.Message;
                }
                return ResultData;
            }
        }

        /// <summary>
        /// 解析接收字节数据
        /// </summary>
        /// <param name="argBytes"></param>
        /// <returns></returns>
        protected override IDeviceData<IDevice<IDevicePara>>? ParseDeviceData(byte[] argBytes)
        {
            AsciiSlaveData asciiSlaveData = new AsciiSlaveData();
            asciiSlaveData.UpdateData(argBytes);
            return new DeviceDataAcsii<IDevice<IDevicePara>>((IDevice<IDevicePara>)this, asciiSlaveData);
        }
    }
}
